package com.machine.filling.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import com.machine.filling.db.dao.GunInfoDao;
import com.machine.filling.db.modle.GunInfoModle;
import com.machine.filling.util.CrcUtil;
import com.machine.filling.util.LogUtil;
import com.machine.filling.util.NumberUtil;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by 86178 on 2019/7/15.
 * author mogen
 * 用心，成就一切。
 */

public class BackService extends Service {

    private static final long HEART_BEAT_RATE = 500 * 3;
    //    public static final String HOST = "11.0.31.52";
    //    public static final String HOST = "192.168.1.224";
    //    public static final int PORT = 8765;
    public static final String HOST = "192.168.1.48";
    public static final String PORT = "8765";
    String moduleGunNum = "two";
    String firstGunNum = "";
    String secondGunNum = "";
    String thirdGunNum = "";
    String forthGunNum = "";
    List<GunInfoModle> list = new ArrayList<>();

    public static final String MESSAGE_ACTION = "org.feng.message_ACTION";
    public static final String HEART_BEAT_ACTION = "org.feng.heart_beat_ACTION";
    private ReadThread mReadThread;
    private WeakReference<Socket> mSocket;
    public byte[] sendBytesToService;
    //循环请求数据
    int isR = 1;

    private Handler mHandler = new Handler();
    private Runnable heartBeatRunnable = new Runnable() {
        @Override
        public void run() {
            if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
                boolean isSuccess = false;
                switch (moduleGunNum) {
                    case "two":
                        if (isR == 1) {
                            isR = 2;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(firstGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 2) {
                            isR = 1;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(secondGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 5) {
                            isSuccess = sendBytes(sendBytesToService);
                            LogUtil.e("log", "发送定量去2-->" + sendBytesToService + "\n发送是否成功-->" + isSuccess);
                            if (isSuccess) {
                                isR = 1;
                            }
                        }
                        break;
                    case "three":
                        if (isR == 1) {
                            isR = 2;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(firstGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 2) {
                            isR = 3;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(secondGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 3) {
                            isR = 1;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(thirdGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 5) {
                            isSuccess = sendBytes(sendBytesToService);
                            LogUtil.e("log", "发送定量去2-->" + sendBytesToService + "\n发送是否成功-->" + isSuccess);
                            if (isSuccess) {
                                isR = 1;
                            }
                        }
                        break;
                    case "four":
                        if (isR == 1) {
                            isR = 2;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(firstGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 2) {
                            isR = 3;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(secondGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 3) {
                            isR = 4;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(thirdGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 4) {
                            isR = 1;
                            sendBytesToService = sendOilGunBytesSecond(sendOilGunBytes(forthGunNum));
                            isSuccess = sendBytes(sendBytesToService);
                        } else if (isR == 5) {
                            isSuccess = sendBytes(sendBytesToService);
                            LogUtil.e("log", "发送定量去2-->" + sendBytesToService + "\n发送是否成功-->" + isSuccess);
                            if (isSuccess) {
                                isR = 1;
                            }
                        }
                        break;
                    default:
                }

                if (!isSuccess) {
                    mHandler.removeCallbacks(heartBeatRunnable);
                    mReadThread.release();
                    releaseLastSocket(mSocket);
                    new InitSocketThread().start();
                }
            }
            mHandler.postDelayed(this, HEART_BEAT_RATE);
        }
    };


    private byte[] sendOilGunBytes(String gunNum) {
        byte[] gunNums = NumberUtil.IntToByte(Integer.parseInt(gunNum, 16));
        byte[] data = new byte[6];
        data[0] = (byte) 0xFA;
        data[1] = (byte) 00;
        data[2] = (byte) 0x03;
        data[3] = (byte) 0x31;
        data[4] = gunNums[gunNums.length - 1];
        data[5] = (byte) 00;
        return data;
    }

    private byte[] sendOilGunBytesSecond(byte[] guns) {
        byte[] crcs = NumberUtil.hexStrTobytes(CrcUtil.getCRC16(guns));
        byte[] data = new byte[8];
        data[0] = guns[0];
        data[1] = guns[1];
        data[2] = guns[2];
        data[3] = guns[3];
        data[4] = guns[4];
        data[5] = guns[5];
        data[6] = crcs[0];
        data[7] = crcs[1];
        return data;
    }

    private long sendTime = 0L;

    @Override
    public IBinder onBind(Intent arg0) {
        return bind;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        LogUtil.e("初始化socket线程");
        new InitSocketThread().start();
    }

    public boolean sendBytes(byte[] datas) {
        if (null == mSocket || null == mSocket.get()) {
            return false;
        }
        Socket soc = mSocket.get();
        try {
            if (!soc.isClosed() && !soc.isOutputShutdown()) {
                OutputStream os = soc.getOutputStream();
                os.write(datas);
                os.flush();
                sendTime = System.currentTimeMillis();
            } else {
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private void initSocket() {
        try {
            list = GunInfoDao.getInstance().queryAll();
            firstGunNum = list.get(0).getGunName();
            secondGunNum = list.get(1).getGunName();

            LogUtil.e("第一条枪name-->"+ list.get(0).getGunName() + "  id-->"+ list.get(0).getGunId()
                    + " gunNum-->"+ list.get(0).getGunNum());
            LogUtil.e("第二条枪name-->"+ list.get(1).getGunName() + "  id-->"+ list.get(1).getGunId()
                    + " gunNum-->"+ list.get(1).getGunNum());

        } catch (Exception e) {
            LogUtil.e("数据库读取枪数据有误");
        }

        try {
            LogUtil.e("IP地址-->" + HOST + "  端口-->" + PORT);
            Socket so = new Socket(HOST, Integer.valueOf(PORT));
            mSocket = new WeakReference<>(so);
            mReadThread = new ReadThread(so);
            mReadThread.start();
            mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);
        } catch (UnknownHostException e) {
            e.printStackTrace();
            LogUtil.e("socket创建失败");
        } catch (IOException e) {
            e.printStackTrace();
            LogUtil.e("socket创建失败");
        }
    }

    private void releaseLastSocket(WeakReference<Socket> mSocket) {
        try {
            if (null != mSocket) {
                Socket sk = mSocket.get();
                if (!sk.isClosed()) {
                    sk.close();
                }
                sk = null;
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class InitSocketThread extends Thread {
        @Override
        public void run() {
            super.run();
            initSocket();
        }
    }

    class ReadThread extends Thread {
        private WeakReference<Socket> mWeakSocket;

        public ReadThread(Socket socket) {
            mWeakSocket = new WeakReference<>(socket);
        }

        public void release() {
            releaseLastSocket(mWeakSocket);
        }

        @Override
        public void run() {
            super.run();
            Socket socket = mWeakSocket.get();
            if (null != socket) {
                try {
                    InputStream is = socket.getInputStream();
                    byte[] buffer = new byte[1024 * 4];
                    int length = 0;
                    while (!socket.isClosed() && !socket.isInputShutdown() && ((length = is.read(buffer)) != -1)) {
                        if (length > 0) {
                            byte[] data = Arrays.copyOf(buffer, length);
                            //1 判断返回值合法性
                            if (!"FA".equals(NumberUtil.getStringByByte(data[0]))) {
                                LogUtil.e("非合法返回值");
                            } else {
                                //2 解析返回值
                                //                                LogUtil.e("接收到数据-->" + NumberUtil.bytesToHexString(data));
                                //                                parse(data);
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public MyBinder bind = new MyBinder();

    public class MyBinder extends Binder {
        public BackService getService() {
            return BackService.this;
        }
    }

    /**
     * 解析返回值
     * 判断逻辑
     * Handle:
     * 0x31  读取油枪实时数据
     * 0x32  外部发送定量
     * 0x33  外部读取最后一次计量交易
     * 0x34  外部直通打印
     * 0x35  外部发送车牌号
     * 0x36  外部直通语音
     * 0x37  插拔卡信息
     * 0x80  认证
     */

    public void parse(byte[] bytes) {
        switch (NumberUtil.getStringByByte(bytes[3])) {
            case "31":
                /**
                 * fa 00 25 31 08 00 02 03 01 f4 00 00 23 00 00 af 00 00 a7 f3 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 eb 63
                 * fa 00 25 31 08 00 35 23 01 f4 00 00 98 00 02 f8 00 00 a7 d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 14 b9
                 * fa         头
                 * 00 25      handle + data 总长
                 * 31         handler
                 * 08         枪号
                 * 00 35      支付  -->这里协议上说是外部支付相关。 协议上的一个字节，这里是两个字节
                 * 23         ST2   -->加油状态
                 * 01 f4      价格
                 * 00 00 98   升数
                 * 00 02 f8   金额
                 * 00 00 a7 d0  升数累计
                 * TODO 油品名称 文本
                 */
                LogUtil.e("读取油枪实时数据");
                byte[] bs = new byte[1];
                bs[0] = bytes[4];
                String t = NumberUtil.toFullBinaryString(Integer.valueOf(NumberUtil.bytesToHexString(bs)));
                if (t.length() > 8) {
                    t = t.substring(t.length() - 8, t.length());
                }
                //注1：当BIT7为1，bit3-0为6时为加油开始。当BIT7为0，bit3-0 <=3 时为加油结束
                if ("1".equals(t.charAt(0)) && NumberUtil.twoChangeToTen(t.substring(t.length() - 4, t.length())) == 6) {
                    LogUtil.e("开始加油");
                }
                if ("0".equals(t.charAt(0)) && NumberUtil.twoChangeToTen(t.substring(t.length() - 4, t.length())) <= 3) {
                    LogUtil.e("加油结束");
                }
                /**
                 * 加油状态
                 * Bit7:枪状态。0：油枪挂枪，1：油枪抬起。
                 * Bit5 ,0:无外部定量，1：有外部有定量
                 * Bit4： 保留；
                 * bit3-0:   2:pc锁定 3:空闲   4:申请中油管控授权  5:中油管控已授权    6:开始加油   8/9:正在加油
                 * 注1：当BIT7为1，bit3-0为6时为加油开始。当BIT7为0，bit3-0 <=3 时为加油结束。
                 */
                LogUtil.e("加油状态-->" + t);
                if ("0".equals(t.charAt(0))) {
                    LogUtil.e("枪状态-->油枪挂枪");
                } else {
                    LogUtil.e("枪状态-->油枪抬起");
                }

                if ("0".equals(t.charAt(2))) {
                    LogUtil.e("无外部定量");
                } else {
                    LogUtil.e("有外部有定量");
                }

                //截取bit3 - 0,转换int
                String last = t.substring(t.length() - 4, t.length());
                LogUtil.e("截图bit转换成int-->" + NumberUtil.twoChangeToTen(last));
                //判断bit3 - 0
                switch (NumberUtil.twoChangeToTen(last)) {
                    case 2:
                        LogUtil.e("pc锁定");
                        break;
                    case 3:
                        LogUtil.e("空闲");
                        break;
                    case 4:
                        LogUtil.e("申请中油管控授权");
                        break;
                    case 5:
                        LogUtil.e("中油管控已授权");
                        break;
                    case 6:
                        LogUtil.e("开始加油");
                        break;
                    case 8:
                        LogUtil.e("正在加油");
                        break;
                    case 9:
                        LogUtil.e("正在加油");
                        break;
                    default:
                }

                //价格
                byte[] bytePrice = new byte[2];
                bytePrice[0] = bytes[8];
                bytePrice[1] = bytes[9];
                LogUtil.e("油品价格-->" + NumberUtil.saveTwo(NumberUtil.hexStringToAlgorism(NumberUtil.bytesToHexString(bytePrice))));

                //升数
                byte[] byteListerNum = new byte[3];
                byteListerNum[0] = bytes[10];
                byteListerNum[1] = bytes[11];
                byteListerNum[2] = bytes[12];
                LogUtil.e("油品升数-->" + NumberUtil.saveTwo(NumberUtil.hexStringToAlgorism(NumberUtil.bytesToHexString(byteListerNum))));

                //金额
                byte[] byteMoney = new byte[3];
                byteMoney[0] = bytes[13];
                byteMoney[1] = bytes[14];
                byteMoney[2] = bytes[15];
                LogUtil.e("加油金额-->" + NumberUtil.saveTwo(NumberUtil.hexStringToAlgorism(NumberUtil.bytesToHexString(byteMoney))));

                break;
            case "32":
                LogUtil.e("外部发送定量");

                break;
            case "33":
                LogUtil.e("外部读取最后一次计量交易");

                break;
            case "34":
                LogUtil.e("外部直通打印");

                break;
            case "35":
                LogUtil.e("外部发送车牌号");

                break;
            case "36":
                LogUtil.e("外部直通语音");

                break;
            case "37":
                LogUtil.e("插拔卡信息");

                break;
            case "80":
                LogUtil.e("认证");

                break;
            default:
        }
    }

    Intent intentDelete;

    public void sentBroadcastDelete(String s) {
        if (intentDelete == null) {
            intentDelete = new Intent();
            intentDelete.setAction("module_service_back");
        }
        intentDelete.putExtra("module_back_info", s);
        sendBroadcast(intentDelete);
    }

}
